ECS(Fargate)上に構築したLocustからAPIサーバ(Go)経由で、TiDB Cloudにクエリを実行してみた

ECS(Fargate)上に構築したLocustからAPIサーバ(Go)経由で、TiDB Cloudにクエリを実行してみた

Clock Icon2024.09.06

こんにちは、ゲームソリューション部のsoraです。
今回は、ECS(Fargate)上に構築したLocustからAPIサーバ(Go)経由で、TiDB Cloudにクエリを実行してみたことについて書いていきます。

TiDB Cloudクラスタの作成

まずTiDB Cloudにてクラスタを作成します。
今回はServerlessクラスタを作成します。
デフォルトで取得できるデータしか使用しないため、クラスタ作成して以下の接続コードを取得する以外の設定は不要です。
sr-ecs-locust-go-tidb01

イメージの作成

dockerfileは以下折り畳みで記載します。

APIサーバ(Go)のdockerfile
FROM golang:alpine

WORKDIR /app

RUN apk update && apk add --no-cache git

COPY /src .
RUN go mod init app
RUN go mod tidy

CMD ["go", "run", "main.go"]
Locustのdockerfile
FROM locustio/locust

WORKDIR /locust

COPY locustfile.py /locust/locustfile.py

CMD ["-f", "/locust/locustfile.py"]

上記は以下記事にて作成したものを使用しております。
https://dev.classmethod.jp/articles/ecs-locust-api-service-connect/

APIサーバ

APIサーバ(Go)のコードは以下です。
/locust-testにリクエストがあった場合に、TiDB Cloudにクエリを実行するコードとなっています。
今回はテストのため、TiDB CloudのServerlessクラスタとはPublicで接続します。

main.go
package main

import (
	"database/sql"
	"log"
	"net/http"
	"crypto/tls"
	"github.com/go-sql-driver/mysql"
)

// 起動するポート
const port = "8080"

func helloHandler(w http.ResponseWriter, r *http.Request) {
	// データベース接続
	// TiDB Cloudにて表示されたコード
	mysql.RegisterTLSConfig("tidb", &tls.Config{
		MinVersion: tls.VersionTLS12,
		ServerName: "gateway01.ap-northeast-1.prod.aws.tidbcloud.com",
	})
	db, err := sql.Open("mysql", "xxxxxxxxxx.root:xxxxxxxxxx@tcp(gateway01.ap-northeast-1.prod.aws.tidbcloud.com:4000)/test?tls=tidb")
    // エラー処理
	if err != nil {
		http.Error(w, "Failed to connect to database", http.StatusInternalServerError)
		log.Printf("Failed to connect to database: %v", err)
		return
	}
	// 関数終了時にコネクションを閉じる
	defer db.Close()

	// クエリ実行
	rows, err := db.Query("SHOW DATABASES")
	if err != nil {
		http.Error(w, "Failed to execute query", http.StatusInternalServerError)
		log.Printf("Failed to execute query: %v", err)
		return
	}
    // 終了後にクエリ結果をリリース
	defer rows.Close()

	// クエリ結果をログ出力
	for rows.Next() {
		var dbName string
		if err := rows.Scan(&dbName); err != nil {
			log.Printf("Failed to scan row: %v", err)
			return
		}
		log.Printf("%s", dbName)
	}

	if err = rows.Err(); err != nil {
		log.Printf("Error occurred during rows iteration: %v", err)
		return
	}
}

func main() {
	// ハンドラ関数を設定
	http.HandleFunc("/locust-test", helloHandler)
	// ログ出力
	log.Printf("Server is running on port %s\n", port)
	// サーバの起動
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}

Locust

Locustのシナリオファイルは、/locust-testにGETリクエストを実行するものとしています。
接続先ホストはGUI上で指定するため、シナリオファイルでは指定していません。

locustfile.py
from locust import HttpUser, task, between

class QuickstartUser(HttpUser):
    # ユーザーが次のタスクを実行するまでの待ち時間を1秒から2.5秒の間でランダムに設定
    wait_time = between(1, 2.5)

    # 負荷テスト中に行われるタスク
    @task
    def index_page(self):
        self.client.get("/locust-test")

ECSタスク定義・サービスの立ち上げ

Locust・APIサーバ間はService Connectで接続します。
ログについて、APIサーバのタスク定義にてログドライバーをawslogsとして、アプリのログをCloudWatch Logsに出力するようにしています。
Service Connectのログも有効化しています。

接続確認

クラスタ内に2つのサービスがそれぞれ起動した後、http://{LocustのタスクのPublic IPアドレス}:8089に接続して、HostとしてAPIサーバのService Connectのエンドポイントを指定すると、正常に実行できていることが確認できました。
sr-ecs-locust-go-tidb02
sr-ecs-locust-go-tidb03
CloudWatch Logsにてログを見てみると、クエリ実行により取得した結果が出力されていることが確認できました。
sr-ecs-locust-go-tidb04
TiDB Cloudでもメトリクスを確認してみると、クエリが実行されていることが確認できました。
sr-ecs-locust-go-tidb05

最後に

今回は、ECS(Fargate)上に構築したLocustからAPIサーバ(Go)経由で、TiDB Cloudにクエリを実行してみたことを記事にしました。
どなたかの参考になると幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.